package pathways.marvin_test;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.InputStream;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;

import pathways.CCompound;
import pathways.CEnzyme;
import pathways.CReaction;
import pathways.Database.Implementation.CDatabase;
import chemaxon.formats.MolImporter;
import chemaxon.marvin.beans.MViewPane;
import chemaxon.struc.MolAtom;
import chemaxon.struc.Molecule;

/**
 * Title:
 * Description:
 * Copyright:    Copyright (c) 2001
 * Company:
 * @author Jia An Chen
 * @version 1.0
 */

public class AtomTraceFrame extends JFrame {

  private CReaction rxn;
  private Vector substrates;
  private Vector products;
  private Vector substrateMolecules = new Vector();
  private Vector substrateViewers = new Vector();
  private Vector productMolecules = new Vector();
  private Vector productViewers = new Vector();
  private JTable[] m_tables;
  private AtomTraceEditorTableModel[] m_data;
  private JLabel productLabel;
  private JLabel substrateLabel;
  private CardLayout cardLayout;
  private JPanel tablePanel;
  private JComboBox productComboBox;
  private JComboBox[] toColumnComboBox;
  private int selectedTable = 0;
  private String[] productNames;
  private JScrollPane substrateSPane;
  private JScrollPane productSPane;
  private static String[] tempStr = {" "};
  private static JComboBox emptyComboBox = new JComboBox(tempStr);
  private CDatabase db;

  public AtomTraceFrame(CReaction rxn, CDatabase database) {
    this("Atom Trace Window", rxn,database);
  }

  public AtomTraceFrame(String title, CReaction rxn, CDatabase dataBase) {
    super(title);
    this.setSize(630, 500);
    this.rxn = rxn;
    this.db = dataBase;

    this.substrates = rxn.getSubstratesWithFile();
    this.products = rxn.getProductsWithFile();
    CEnzyme enzyme = rxn.getEnzyme();

    InputStream inputFile;

    Molecule tempMol;
    MViewPane tempViewer;
    JPanel substratePanel = new JPanel(new GridLayout(substrates.size(), 1, 10, 10));
    for (int i = 0; i < substrates.size(); i++) {
      JPanel tempViewPane = new JPanel(new BorderLayout());
//      tempViewPane.add(new JLabel(((CCompound)substrates.get(i)).getName(), JLabel.CENTER), BorderLayout.NORTH);

      inputFile = ((CCompound)substrates.get(i)).getFile();
      try {
        MolImporter mi = new MolImporter(inputFile);
        tempMol = mi.read();

        tempViewer = new ConfiguredMarvinPane();
        tempViewer.setM(0, tempMol);
        tempViewPane.add(tempViewer, BorderLayout.CENTER);

        substrateMolecules.add(i, tempMol);
        substrateViewers.add(i, tempViewer);

        final int substrateNum = i;
        tempViewer.addMouseListener(new MouseListener() {
          public void mousePressed(MouseEvent e) {
            AtomTraceFrame.this.substrateViewerSelected(substrateNum);
          }
          public void mouseClicked(MouseEvent e) {
            AtomTraceFrame.this.substrateViewerSelected(substrateNum);
          }

          public void mouseReleased(MouseEvent e) {
          }
          public void mouseEntered(MouseEvent e) {
          }
          public void mouseExited(MouseEvent e) {
          }
        });

        tempViewPane.setBorder(BorderFactory.createTitledBorder(
                               BorderFactory.createEtchedBorder(Color.cyan, Color.blue), ((CCompound)substrates.get(i)).getName()));
        substratePanel.add(tempViewPane);
      }
      catch(Exception ex) {
        ex.printStackTrace();
      }
    }

    Container contentPane = this.getContentPane();

    if (substrateViewers.size() > 0 && products.size() > 0){
      ((MViewPane)substrateViewers.get(0)).setSelectedIndex(0);

      substrateSPane = new JScrollPane(substratePanel);
      substrateSPane.setPreferredSize(new Dimension(300, 300));

      // Creating the panel for displaying the product molecules
      JPanel productPanel = new JPanel(new GridLayout(products.size(), 1, 10, 10));
      productNames = new String[products.size()+1];
      productNames[0] = " ";
      toColumnComboBox = new JComboBox[products.size()];
      for (int i = 0; i < products.size(); i++) {
        productNames[i+1] = ((CCompound)products.get(i)).getName();

        JPanel tempViewPane = new JPanel(new BorderLayout());
        inputFile = ((CCompound)products.get(i)).getFile();
        try {
          MolImporter mi = new MolImporter(inputFile);
          tempMol = mi.read();

          tempViewer = new ConfiguredMarvinPane();
          tempViewer.setM(0, tempMol);

          productMolecules.add(i, tempMol);

          String[] toChoices = new String[tempMol.getAtomCount()+1];
          toChoices[0] = " ";
          for (int j = 1; j <= tempMol.getAtomCount(); j++) {
            toChoices[j] = String.valueOf(j);
          }
          toColumnComboBox[i] = new JComboBox(toChoices);

          tempViewPane.add(tempViewer, BorderLayout.CENTER);
          productViewers.add(i, tempViewer);

          final int productNum = i;
          tempViewer.addMouseListener(new MouseListener() {
            public void mousePressed(MouseEvent e) {
              AtomTraceFrame.this.productViewerSelected(productNum);
            }
            public void mouseClicked(MouseEvent e) {
              AtomTraceFrame.this.productViewerSelected(productNum);
            }

            public void mouseReleased(MouseEvent e) {
            }
            public void mouseEntered(MouseEvent e) {
            }
            public void mouseExited(MouseEvent e) {
            }
          });

          tempViewPane.setBorder(BorderFactory.createTitledBorder(
                                 BorderFactory.createEtchedBorder(Color.orange, Color.red), ((CCompound)products.get(i)).getName()));
          productPanel.add(tempViewPane);
        }
        catch(Exception ex) {
          ex.printStackTrace();
        }
      }
      productComboBox = new JComboBox(productNames);
      productComboBox.addItemListener(new ItemListener() {
        public void itemStateChanged(ItemEvent ie) {
          if (ie.getStateChange() == ItemEvent.SELECTED
              && !((String)ie.getItem()).equals(" ") ) {
            AtomTraceFrame.this.productSelected(((JComboBox)ie.getItemSelectable()).getSelectedIndex()-1);
          }
        }
      });

      productSPane = new JScrollPane(productPanel);
      productSPane.setPreferredSize(new Dimension(300, 300));

      JPanel moleculePanel = new JPanel();

      moleculePanel.setLayout(new GridLayout(1, 2, 10, 18));
      moleculePanel.setPreferredSize(new Dimension(618, 300));

      moleculePanel.add(substrateSPane);
      moleculePanel.add(productSPane);

      JPanel mainPanel = new JPanel(new BorderLayout());
      mainPanel.add(moleculePanel, BorderLayout.CENTER);

      JPanel namePanel = new JPanel(new GridLayout(1, 3));
      substrateLabel = new JLabel("Substrate: " + ((CCompound)substrates.get(0)).getName(), JLabel.CENTER);
      productLabel = new JLabel("Product: " + ((CCompound)products.get(0)).getName(), JLabel.CENTER);

      //JiaAn???
      namePanel.add(substrateLabel);
      JLabel enzymeLabel = new JLabel("== Enzyme: " + enzyme.getName() + " =>", JLabel.CENTER);
      enzymeLabel.setForeground(Color.magenta);
      namePanel.add(enzymeLabel);
      namePanel.add(productLabel);

      mainPanel.add(namePanel, BorderLayout.SOUTH);

      contentPane.setLayout(new BorderLayout());

      contentPane.add(mainPanel, BorderLayout.CENTER);

      m_data = new AtomTraceEditorTableModel[substrates.size()];
      m_tables = new JTable[substrates.size()];
      JScrollPane[] jsps = new JScrollPane[substrates.size()];
      for (int i = 0; i < substrates.size(); i++) {
        m_data[i] = new AtomTraceEditorTableModel(((Molecule)substrateMolecules.get(i)).getAtomCount(), this);
        m_tables[i] = new JTable();
        m_tables[i].setAutoCreateColumnsFromModel(false);
        m_tables[i].setModel(m_data[i]);
        m_tables[i].setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        for (int k = 0; k < AtomTraceEditorTableModel.m_columns.length; k++) {
          TableCellRenderer renderer;
          TableCellEditor editor;

          DefaultTableCellRenderer textRenderer = new DefaultTableCellRenderer();
          textRenderer.setHorizontalAlignment(AtomTraceEditorTableModel.m_columns[k].m_alignment);
          renderer = textRenderer;

          if (k == AtomTraceEditorTableModel.COL_PROD) {
            editor = new DefaultCellEditor(productComboBox);
          }
          else if (k == AtomTraceEditorTableModel.COL_TO) {
            editor = new DefaultCellEditor(emptyComboBox);
          }
          else {
            editor = null;
          }

          TableColumn column = new TableColumn(k, AtomTraceEditorTableModel.m_columns[k].m_width, renderer, editor);
          column.setIdentifier(Integer.toString(k));
          m_tables[i].addColumn(column);
        }

        m_tables[i].setRowSelectionInterval(0, 0);
        JTableHeader header = m_tables[i].getTableHeader();
        header.setUpdateTableInRealTime(false);

        jsps[i] = new JScrollPane();
        jsps[i].getViewport().add(m_tables[i]);
        jsps[i].setPreferredSize(new Dimension(618, 110));

        final int tableNum = i;
        m_tables[i].addMouseListener(new MouseListener() {
          public void mouseReleased(MouseEvent e) {
            AtomTraceFrame.this.colorAtoms(tableNum);
          }

          public void mouseClicked(MouseEvent e) {
          }
          public void mousePressed(MouseEvent e) {
          }
          public void mouseEntered(MouseEvent e) {
          }
          public void mouseExited(MouseEvent e) {
          }
        });
//        m_tables[i].addMouseListener(new AtomTraceEditTableSelectListener(this));
      }

  // VJ???
      IAtomTraceDatabase database = CAtomTraceDatabase.create(db);

      ResultSet resultSet = database.getAtomTraces(rxn);

      try {
        if (resultSet != null) {
          long substrateID;
          long prodID;
          int rowNum;
          int toAtomNum;

          while (resultSet.next()) {
            substrateID = resultSet.getLong(1);
            prodID = resultSet.getLong(2);
            rowNum = resultSet.getInt(3);
            toAtomNum = resultSet.getInt(4);
            int substrateIndex;
            for (substrateIndex = 0; substrateIndex < substrates.size(); substrateIndex++) {
              if (((CCompound)substrates.get(substrateIndex)).getID() == substrateID) {
                break;
              }
            }

            int prodIndex;
            for (prodIndex = 0; prodIndex < products.size(); prodIndex++) {
              if (((CCompound)products.get(prodIndex)).getID() == prodID) {
                break;
              }
            }

//            System.out.println(rowNum + "_" + prodIndex + "_" + String.valueOf(toAtomNum));
            if (substrateIndex < substrates.size() && prodIndex < products.size())
              m_data[substrateIndex].setTrace(rowNum-1, this.productNames[prodIndex+1], String.valueOf(toAtomNum));
          }
        }
      }
      catch (SQLException sqle) {
        System.err.println(sqle);
      }

      cardLayout = new CardLayout();
      tablePanel = new JPanel(cardLayout);
      for (int i = 0; i < jsps.length; i++) {
        tablePanel.add(String.valueOf(i), jsps[i]);
      }
      cardLayout.show(tablePanel, String.valueOf(selectedTable));

      JPanel commandPanel = new JPanel(new BorderLayout());
      commandPanel.add(tablePanel, BorderLayout.CENTER);

      JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
      JButton updateButton = new JButton("Update");
      updateButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          AtomTraceFrame.this.updateData();
        }
      });
      buttonPanel.add(updateButton);

      commandPanel.add(buttonPanel, BorderLayout.SOUTH);
      commandPanel.setPreferredSize(new Dimension(618, 147));
      contentPane.add(commandPanel, BorderLayout.SOUTH);

    }
    else {
      contentPane.setLayout(new FlowLayout(FlowLayout.CENTER));
      this.setSize(200, 200);
      Label lb = new Label("No mol files are found for the molecules.");
      contentPane.add(lb);
      JButton btn = new JButton("OK");
      btn.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent ae) {
          dispose();
        }
      });
      contentPane.add(btn);

    }


    this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
  }

  public boolean isAlreadySelected(AtomTraceEditorTableModel model, int nRow, String product, String to) {
    for (int i = 0; i < m_data.length; i++) {
      if (m_data[i].isAlreadySelected(model, nRow, product, to))
        return true;
    }
    return false;
  }

  public void productSelected(int selectedProduct) {
    this.productSPane.getVerticalScrollBar().setValue((int)((productSPane.getVerticalScrollBar().getMaximum()-productSPane.getVerticalScrollBar().getMinimum()) * ((double)selectedProduct / (double)productMolecules.size())));
    for (int i = 0; i < productMolecules.size(); i++) {
      ((MViewPane)productViewers.get(i)).setSelectedIndex(-1);
      ((Molecule)productMolecules.get(i)).setSetSeqs(0);
    }

    ((MViewPane)productViewers.get(selectedProduct)).setSelectedIndex(0);

    m_tables[selectedTable].getColumn("2").setCellEditor(new DefaultCellEditor(toColumnComboBox[selectedProduct]));

//    ((Molecule)productMolecules.get(selectedProduct)).set
  }

  public void substrateViewerSelected(int selectedSubstrateViewer) {
    selectedTable = selectedSubstrateViewer;
    substrateLabel.setText("Substrate: " + ((CCompound)substrates.get(selectedTable)).getName());
    cardLayout.show(tablePanel, String.valueOf(selectedSubstrateViewer));
    colorAtoms();

/*    for (int i = 0; i < substrateViewers.size(); i++) {
      if (i != selectedTable) {
        ((MViewPane)substrateViewers.get(i)).setSelectedIndex(-1);
        ((Molecule)substrateMolecules.get(i)).setSetSeqs(0);
      }
    }*/
  }

  public void productViewerSelected(int selectedProductViewer) {
    for (int i = 0; i < m_tables[selectedTable].getRowCount(); i++) {
      if (((String)m_tables[selectedTable].getValueAt(i, AtomTraceEditorTableModel.COL_TO)).equals(" ")) {
        m_tables[selectedTable].setValueAt(productNames[selectedProductViewer+1],
                                           i,
                                           AtomTraceEditorTableModel.COL_PROD);
      }
    }

/*    m_tables[selectedTable].setValueAt(productNames[selectedProductViewer+1],
                                       m_tables[selectedTable].getSelectedRow(),
                                       AtomTraceEditorTableModel.COL_PROD);
*/
    m_tables[selectedTable].updateUI();

    m_tables[selectedTable].getColumn("2").setCellEditor(new DefaultCellEditor(toColumnComboBox[selectedProductViewer]));

    for (int i = 0; i < productMolecules.size(); i++) {
      ((MViewPane)productViewers.get(i)).setSelectedIndex(-1);
      ((Molecule)productMolecules.get(i)).setSetSeqs(0);
    }

    ((MViewPane)productViewers.get(selectedProductViewer)).setSelectedIndex(0);

    colorAtoms();
  }

  public void colorAtoms() {
    this.colorAtoms(this.selectedTable);
  }

  public void colorAtoms(int selectedTable) {
    clearSubstrates();
    clearProducts();

    ((MViewPane)substrateViewers.get(selectedTable)).setSelectedIndex(0);

    int selectedRow = m_tables[selectedTable].getSelectedRow();

    if (selectedRow > -1) {
      String[] rowData = new String[AtomTraceEditorTableModel.m_columns.length];
      for (int i = 0; i < rowData.length; i++) {
        rowData[i] = (String)m_data[selectedTable].getValueAt(selectedRow, i);
      }

      MolAtom atom;
      atom = ((Molecule)substrateMolecules.get(selectedTable)).getAtom(Integer.parseInt(rowData[0])-1);
      atom.setSetSeq(1);
      ((MViewPane)substrateViewers.get(selectedTable)).repaint();

      int selectedProduct = -1;
      for (int i = 0; i < products.size(); i++) {
        if (((CCompound)products.get(i)).getName().equals(rowData[1])) {
          selectedProduct = i;
          break;
        }
      }

      if (selectedProduct != -1) {
        this.productSPane.getVerticalScrollBar().setValue((int)((productSPane.getVerticalScrollBar().getMaximum()-productSPane.getVerticalScrollBar().getMinimum()) * ((double)selectedProduct / (double)productMolecules.size())));
        ((MViewPane)productViewers.get(selectedProduct)).setSelectedIndex(0);
        try {
          atom = ((Molecule)productMolecules.get(selectedProduct)).getAtom(Integer.parseInt(rowData[2])-1);
          atom.setSetSeq(1);
          ((MViewPane)productViewers.get(selectedProduct)).repaint();
        }
        catch (NumberFormatException nfe) {
          return;
        }
      }
    }
  }

  public void setAtomChoiceEmpty(int nRow) {
      m_tables[selectedTable].getColumn("2").setCellEditor(new DefaultCellEditor(emptyComboBox));
      m_tables[selectedTable].setValueAt(" ",nRow ,2);
  }

  private void clearSubstrates() {
    for (int i = 0; i < substrateViewers.size(); i++) {
      ((MViewPane)substrateViewers.get(i)).setSelectedIndex(-1);
      ((Molecule)substrateMolecules.get(i)).setSetSeqs(0);
      ((MViewPane)substrateViewers.get(i)).repaint();
    }
  }

  private void clearProducts() {
    for (int i = 0; i < productViewers.size(); i++) {
      ((MViewPane)productViewers.get(i)).setSelectedIndex(-1);
      ((Molecule)productMolecules.get(i)).setSetSeqs(0);
      ((MViewPane)productViewers.get(i)).repaint();
    }
  }

  protected void updateData() {
    Vector traceIDPaths = new Vector();
    Vector tracePaths;
    CTracePath path;
    for (int i = 0; i < m_data.length; i++) {
      tracePaths = m_data[i].getTracePaths();
      for (int j = 0; j < tracePaths.size(); j++) {
        path = (CTracePath)tracePaths.get(j);
        int z;
        for (z = 0; z < products.size(); z++) {
          if (path.m_product.equals(((CCompound)products.get(z)).getName()))
            break;
        }
        CTraceIDPath idPath = new CTraceIDPath(((CCompound)substrates.get(i)).getID(),
                                               Integer.parseInt(path.m_from),
                                               ((CCompound)products.get(z)).getID(),
                                               Integer.parseInt(path.m_to)
                                               );
        traceIDPaths.add(idPath);
      }
    }

    IAtomTraceDatabase database = CAtomTraceDatabase.create(db);
    if (database.updateAtomTrace(this.rxn.getID(), traceIDPaths)) {
      JOptionPane.showMessageDialog(this, "Data updated successfully", "Data Update Dialog", JOptionPane.INFORMATION_MESSAGE);
    }
    else {
      JOptionPane.showMessageDialog(this, "Errors occured!", "Data Update Dialog", JOptionPane.ERROR_MESSAGE);
    }

    this.setVisible(false);
    this.dispose();
  }

  public static void main(String[] args) {

  // VJ???
    /*CSubstrate s = new CSubstrate("fdsa", 323, new Rectangle(0, 0, 0, 0));
    CReaction rxn = new CReaction(new CSubstrate("asdf", 123, new Rectangle(0, 0, 0, 0)), new CEnzyme("enzyme", 21), s, 2, 0,0);
    JFrame mainFrame = new AtomTraceFrame(rxn);
    mainFrame.setLocation(300, 300);
    mainFrame.pack();
    mainFrame.show();*/
  }
}
